import React, {FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
import {closeModal, updataModalFooter} from "../../services/ModalService";
import {createParams, isString} from "../../utils";
import {AxiosUpload} from "../../services/HttpService";
import {Button, message, Spin, Upload} from "antd";
import {useTranslation} from "react-i18next";
import useStateRef from "../../customUse/useStateRef";
import useThrottle from "../../customUse/useThrottle";
import {getFormView, getFormViewList} from "../../services/ViewService";
import BaseForm from "../../module/form/BaseForm.tsx";
import GlobalIcon from "../../global/GlobalIcon.tsx";
import {showMessage} from "../../reducer/MsgReducer.tsx";

interface UploadModalProps {
    modalKey?: string,
    accept?: string,
    view?: string,
    url: string,
    mode?: "single" | "multiple",
    isNowUpload?: boolean,
    dataSource?: any
}

const UploadModal: FC<UploadModalProps> = (props) => {

    const {t} = useTranslation();
    const fromRef = useRef();
    const fileListRef = useRef([]);
    const loadingCountRef = useRef(0);

    const [fileList, setFileList] = useStateRef([], fileListRef),
        [view, setView] = useState<any[]>([]),
        [loading, setLoading] = useStateRef(0, loadingCountRef);

    const uploadFile: Function = useCallback(async (file: any) => {
        const {url}: { url: string } = props;
        if (!url) {
            return false
        }
        const values: any = await fromRef.current.validateFields();
        let params = createParams({...values}, props);
        let formData = new FormData();
        for (let key in params) {
            formData.append(key, params[key] || '');
        }
        formData.append("file", file);
        setLoading((loadingCountRef.current + 1));
        try {
            const res = await AxiosUpload(url, formData);
            setLoading((loadingCountRef.current - 1));
            showMessage({
                type: "success",
                msg: file.name + ':' + res.msg
            })
            return res.data || null;
        } catch (error) {
            setLoading((loadingCountRef.current - 1));
        }
    }, [props])

    const onOk: Function = useThrottle(async () => {
        if (!fileListRef.current.length) {
            return false
        }
        let data: any = [];
        for (let i: number = 0; i < fileListRef.current.length; i++) {
            let file: any = fileListRef.current[i];
            let res = await uploadFile(file);
            if (res) {
                data.push(res);
            }
            if (res === null) {
                if (i == fileListRef.current.length - 1) {
                    showMessage({
                        type: "success",
                        msg: t("operationSuccess")
                    })
                }
            }
        }
        await closeModal(props.modalKey, async () => {
            return {data: data};
        });
    }, 2000, [props, fileList]);

    const setFileValue: Function = useCallback((files: any[]) => {
        let newFileList: any[] = [...(fileListRef.current || []), ...files];
        setFileList(newFileList);
    }, [fileList, props.mode]);

    const handleUploadFile: Function = useCallback(async (file: any) => {
        const {accept = ""}: { accept: string } = props;
        if (accept && accept.indexOf(file.name.split(".")[1]) === -1) {
            showMessage({
                type: "error",
                msg: t("limitFileType", {suffix: accept})
            })
            return false;
        }
        setFileValue([file])
        if (props.isNowUpload) {
            onOk()
        }
    }, [props]);

    const handleRemove: Function = useCallback((file: any) => {
        let newFileList: any[] = [...fileList];
        let index: number = fileList.findIndex(i => (i.uid === file.uid));
        if (index === -1) {
            return false
        }
        newFileList.splice(index, 1);
        setFileList(newFileList);
    }, [fileList, props.mode]);

    const loadView: Function = useCallback(async (editData: any = {}) => {
        const {view, dataSource}: { view: string, dataSource: any } = props;
        if (isString(view)) {
            let result = await getFormView(view, editData, dataSource);
            if (result.form && props.formatFormView) {
                result.form = await props.formatFormView(result.form, editData);
            }
            setView(result.form);
        } else {
            setView((await getFormViewList(view, editData)).form);
        }
    }, [props]);

    useEffect(() => {
        const {defaultValue = {}}: { defaultValue: any } = props;
        loadView(defaultValue);
    }, [props.view, props.defaultValue]);

    useEffect(() => {
        if (props.isNowUpload) {
            updataModalFooter(props.modalKey, null);
        } else {
            updataModalFooter(props.modalKey, [<Button type="primary" onClick={onOk}>{t("determine")}</Button>])
        }
    }, [props.isNowUpload, props.modalKey]);

    const renderForm = useMemo(() => {
        return (
            <div className="sf_core_upload_modal">
                <BaseForm
                    init={fromRef}
                    view={view}
                />
            </div>
        )
    }, [view]);

    const renderUploadModal = useMemo(() => {
        const {mode = "single", accept = ""}: { mode?: "single" | "multiple", accept: string } = props;
        return (
            <Spin spinning={loading} wrapperClassName="sf_core_upload_modal">
                {renderForm}
                <Upload.Dragger
                    accept={accept}
                    multiple={mode === "multiple" && !props.isNowUpload}
                    fileList={fileList}
                    beforeUpload={(file) => {
                        handleUploadFile(file);
                        return false
                    }}
                    onRemove={(file) => {
                        handleRemove(file);
                        return false
                    }}
                >
                    <GlobalIcon name="icon-upload" size={50} style={{color: "blue"}}/>
                    <p>{t("dragUpload")}</p>
                    {accept ? <p>{t("limitFileType", {suffix: accept})}</p> : null}
                </Upload.Dragger>
            </Spin>
        )
    }, [fileList, props, view, loading])
    return (renderUploadModal);
};

export default React.memo(UploadModal);